</> 技術筆記Tech Notes

細說 JavaScript 函數:從基礎到核心觀念

一、前言:函數不只是功能,更是語言的核心構件

在 JavaScript 中,函數的角色遠不僅止於封裝程式邏輯,它是語言中的一等公民(First-class Citizen)。這代表函數本身可以被賦值給變數、作為參數傳遞,甚至作為其他函數的返回值。本篇文章將由淺入深,帶您系統性地理解 JavaScript 中函數的結構、行為與核心特性。

在本文末會說明何謂一等公民

二、函數的基礎概念:語法、參數與引數

2.1 基本語法與調用方式

在 JavaScript 中,最基本的函數定義方式如下:

javascript複製編輯function functionName(parameter1, parameter2) {
  // 函數主體
}
  • functionName 為函數名稱,可用於之後的調用。

  • parameter1, parameter2 是定義階段的參數,用於接收外部傳入的資料。

範例如下:

javascript複製編輯function hello(name, message) {
  console.log("Hello " + name + ", " + message);
}

hello("Leo Shiang", "How are you?");

2.2 「參數」與「引數」的差異

雖然「參數」(Parameter)與「引數」(Argument)常被混用,但兩者在概念上是不同的:

  • 參數:定義函數時括號中宣告的變數名稱。

  • 引數:實際呼叫函數時傳入的值。

JavaScript 對於引數數量與型態非常寬容:

  • 可以傳入比定義時更多或更少的引數;多餘者會被忽略,未給值者為 undefined

  • 傳入的資料型態不會受限於參數預期型別。


三、深入函數內部:返回值與 arguments 物件

3.1 函數的返回機制

函數可選擇是否使用 return 陳述式返回值:

javascript複製編輯function sum(a, b) {
  return a + b;
}

若未使用 return,函數預設回傳 undefined

javascript複製編輯function sum(a, b) {
  // 無回傳值
}

console.log(sum(1, 2)); // 輸出 undefined

3.2 arguments 物件介紹

在傳統函數中(非箭頭函數),可以透過 arguments 物件存取所有傳入的引數。其特性包括:

  • 類陣列物件,具有 length 屬性與索引存取方式,但並非真正的陣列。

  • 可透過 arguments.length 獲取傳入引數數量。

  • 在非嚴格模式下,arguments 與命名參數是雙向連動的。

範例一:取得引數數量

javascript複製編輯function howManyArgs() {
  console.log(arguments.length);
}

howManyArgs("beauty", "of", "javascript"); // 3

範例二:與命名參數的連動

javascript複製編輯function add(a, b) {
  arguments[1] = 10;
  return a + b; // b 會被修改為 10
}

console.log(add(1, 2)); // 輸出 11

注意:在嚴格模式下 ('use strict'),arguments 與參數之間的連動關係已被取消。


四、函數的本質:可以傳遞的物件

JavaScript 中,函數實際上是 Function 類別的實例。作為物件,它們:

  • 可以擁有自己的屬性與方法。

  • 可以被賦值、傳遞,甚至回傳。

  • 函數名稱實際上是一個指向函數物件的參考。

以下範例說明此特性:

javascript複製編輯function sum(a, b) {
  return a + b;
}

var total = sum;
console.log(total(1, 2)); // 3

sum = null;
console.log(total(1, 2)); // 仍然可執行,輸出 3

五、函數的兩種定義方式:宣告與表示式

5.1 函數宣告(Function Declaration)

使用 function 關鍵字直接定義,具備提升(Hoisting)特性:

javascript複製編輯function sum(a, b) {
  return a + b;
}

5.2 函數表示式(Function Expression)

將匿名函數賦值給變數:

javascript複製編輯var sum = function(a, b) {
  return a + b;
};

5.3 差異說明:Hoisting

  • 函數宣告會被提升:可在宣告前呼叫。

  • 函數表示式僅提升變數名稱:賦值部分不會被提升。

範例如下:

javascript複製編輯console.log(sum(1, 2)); // 可正常執行

function sum(a, b) {
  return a + b;
}
javascript複製編輯console.log(sum(1, 2)); // TypeError: sum is not a function

var sum = function(a, b) {
  return a + b;
};

六、高階應用:函數作為一等公民的實例

函數可作為其他函數的引數或返回值,此能力稱為「高階函數」(Higher-Order Function):

javascript複製編輯function callFunction(fn, value) {
  return fn(value);
}

function add10(num) {
  return num + 10;
}

function greeting(name) {
  return "Hello, " + name;
}

console.log(callFunction(add10, 5));       // 15
console.log(callFunction(greeting, "Leo")) // Hello, Leo

這種設計在現代 JavaScript 開發中極為常見,尤其是在 Promise、事件處理、以及 React 等框架中的函數組件與 Hooks 機制中。

七、補充說明:何謂一等公民?

當一個語言的某種元素被稱為「一等公民」(First-Class Citizen 或 First-Class Object),意思是:它在語言中被當作普通值來處理,具備與其他資料型別(如數字、字串、物件)相同的操作彈性與地位。

在 JavaScript 中,函數就是一等公民,這代表:

  1. 可以賦值給變數

    const sayHi = function() {
      console.log("Hi");
    };
    
  2. 可以作為引數傳遞給其他函數

    function call(fn) {
      fn();
    }
    
    call(sayHi);
    
  3. 可以作為函數的返回值

    function createLogger(msg) {
      return function() {
        console.log(msg);
      };
    }
    
    const logHello = createLogger("Hello");
    logHello(); // 輸出 Hello
    
  4. 可以擁有屬性和方法(因為函數也是物件)

    function greet() {}
    greet.description = "這是一個問候函數";
    console.log(greet.description); // "這是一個問候函數"
    

八、結語

函數是 JavaScript 的核心概念之一,不僅具備高度彈性,更是許多進階應用的基礎。透過理解函數的語法結構、參數傳遞方式,以及其作為一等公民的特性,能有效提升開發效率與程式碼可讀性。

無論是日常開發或框架應用,熟悉函數的本質與運作邏輯,都是成為優秀 JavaScript 開發者不可或缺的一步。希望本文能為您打下穩固的起點。